/*
 *
 */
package org.jiscinvolve.astrodabis.barberry.hibernate.data.normal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.GenerationType;
import javax.persistence.GeneratedValue;

import org.hibernate.annotations.Index;
import org.hibernate.annotations.NamedQuery;
import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.GenericGenerator;

import org.springframework.stereotype.Repository;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; 

import org.jiscinvolve.astrodabis.barberry.common.core.Job;
import org.jiscinvolve.astrodabis.barberry.common.core.Tag;
import org.jiscinvolve.astrodabis.barberry.common.core.Womble;
import org.jiscinvolve.astrodabis.barberry.common.core.Account;
import org.jiscinvolve.astrodabis.barberry.common.core.Identifier;
import org.jiscinvolve.astrodabis.barberry.common.core.SimpleIdent;
import org.jiscinvolve.astrodabis.barberry.common.core.AbstractIdent;
import org.jiscinvolve.astrodabis.barberry.common.core.exception.*;

import org.jiscinvolve.astrodabis.barberry.common.data.RowTag;
import org.jiscinvolve.astrodabis.barberry.common.data.JoinTag;

import org.jiscinvolve.astrodabis.barberry.common.data.TapRow;
import org.jiscinvolve.astrodabis.barberry.common.data.TapJoin;
import org.jiscinvolve.astrodabis.barberry.common.data.TapTable;
import org.jiscinvolve.astrodabis.barberry.common.data.TapColumn;
import org.jiscinvolve.astrodabis.barberry.common.data.TapService;

import org.jiscinvolve.astrodabis.barberry.hibernate.core.JobEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.TagEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.OwnedEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.TrackedEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.AbstractEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.AbstractFactory;

import org.jiscinvolve.astrodabis.barberry.hibernate.annotation.*;

/**
 *
 */
@Entity
@Table(
    name = JoinTagEntity.DB_TABLE_NAME
    )
@NamedQueries(
        {
        @NamedQuery(
            name  = "jointag-all",
            query = "FROM JoinTagEntity ORDER BY ident"
            ),
        @NamedQuery(
            name  = "jointag-join",
            query = "FROM JoinTagEntity WHERE tapjoin = :join"
            ),
        @NamedQuery(
            name  = "jointag-tag",
            query = "FROM JoinTagEntity WHERE tag = :tag"
            ),
        @NamedQuery(
            name  = "jointag-job",
            query = "FROM JoinTagEntity WHERE job = :job"
            ),
        @NamedQuery(
            name  = "jointag-join-tag",
            query = "FROM JoinTagEntity WHERE tapjoin = :join AND tag = :tag"
            ),
        }
    )
public class JoinTagEntity
extends TrackedEntity
implements JoinTag
    {

    /**
     * Our debug logger.
     * 
     */
    private static Log log = LogFactory.getLog(JoinTagEntity.class);

    public static final String DB_TABLE_NAME = "normjointags";
    public static final String DB_IDENT_COL  = "ident";
    public static final String DB_JOIN_COL   = "tapjoin";
    public static final String DB_TAG_COL    = "tag";
    public static final String DB_JOB_COL    = "job";
    public static final String DB_VAL_COL    = "tagvalue";

    @Repository
    public static class Factory
    extends AbstractFactory<JoinTag, JoinTagEntity>
    implements JoinTag.Factory
        {

        @Override
        public Identifier ident(String ident)
            {
            if ((ident == null) || ("-".equals(ident)))
                {
                return null ;
                }
            else {
                try {
                    return new SimpleIdent<Long>(
                        Long.valueOf(
                            ident
                            )
                        );
                    }
                catch (NumberFormatException ouch)
                    {
                    throw new IdentFormatException(
                        ouch
                        );
                    }
                }
            }

        @Override
        @CreateObject
        public JoinTag create(TapJoin join, Job job, Tag tag)
            {
            return createQuick(
                join,
                job,
                tag
                );
            }

        @Override
        @CreateQuick
        public JoinTag createQuick(TapJoin join, Job job, Tag tag)
            {
            return hibernate().insert(
                new JoinTagEntity(
                    join,
                    job,
                    tag
                    )
                );
            }

        @Override
        @CreateObject
        public JoinTag create(TapJoin join, Job job, Tag tag, Double value)
            {
            return createQuick(
                join,
                job,
                tag,
                value
                );
            }

        @Override
        @CreateQuick
        public JoinTag createQuick(TapJoin join, Job job, Tag tag, Double value)
            {
            return hibernate().insert(
                new JoinTagEntity(
                    join,
                    job,
                    tag,
                    value
                    )
                );
            }

        @Override
        @SelectObject
        public JoinTag select(Identifier ident)
            {
            return hibernate().select(
                JoinTagEntity.class,
                ident
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select()
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-all"
                    )
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select(TapJoin join)
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-join"
                    ).setEntity(
                        "join",
                        join
                        )
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select(Tag tag)
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-tag"
                    ).setEntity(
                        "tag",
                        tag
                        )
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select(Job job)
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-job"
                    ).setEntity(
                        "job",
                        job
                        )
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select(Job job, int limit)
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-job"
                    ).setEntity(
                        "job",
                        job
                    ).setMaxResults(
                        limit
                        )
                );
            }

        @Override
        @SelectObject
        public Iterable<JoinTag> select(TapJoin join, Tag tag)
            {
            return hibernate().iterable(
                hibernate().query(
                    "jointag-join-tag"
                    ).setEntity(
                        "join",
                        join
                    ).setEntity(
                        "tag",
                        tag
                        )
                );
            }

        @Override
        @UpdateObject
        public void delete(Tag tag)
            {
//TODO Move this to hibernate()
            template().deleteAll(
                template().find(
                    "FROM JoinTagEntity WHERE tag = ?",
                    tag
                    )
                );
            }

        @Override
        @UpdateObject
        public void delete(Job job)
            {
//TODO Move this to hibernate()
            template().deleteAll(
                template().find(
                    "FROM JoinTagEntity WHERE job = ?",
                    job
                    )
                );
            }

        }

    protected JoinTagEntity()
        {
        super();
        }

    protected JoinTagEntity(TapJoin join, Job job, Tag tag)
        {
        this(
            join,
            job,
            tag,
            null
            );
        }

    protected JoinTagEntity(TapJoin join, Job job, Tag tag, Double value)
        {
        super(true);
        this.job = job ;
        this.tag = tag ;
        this.tapjoin = join ;
        this.value = value  ;
        }

    @Id
    @Column(
        name = DB_IDENT_COL
        )
    @GeneratedValue(
        generator="tapdata-hilo"
        )
    @GenericGenerator(
        name="tapdata-hilo",
        strategy="hilo"
        )
    protected Long ident ;

    @Override
    public Identifier ident()
        {
        return new AbstractIdent()
            {
            @Override
            public Serializable value()
                {
                return ident ;
                }
            };
        }

    @ManyToOne(
        targetEntity = TapJoinEntity.class
        )
    @JoinColumn(
        name = DB_JOIN_COL,
        nullable = false
        )
    private TapJoin tapjoin ;

    @Override
    public TapJoin join()
        {
        return this.tapjoin ;
        }

    @ManyToOne(
        targetEntity = TagEntity.class
        )
    @JoinColumn(
        name = DB_TAG_COL,
        nullable = false
        )
    private Tag tag ;

    @Override
    public Tag tag()
        {
        return this.tag ;
        }

    @ManyToOne(
        targetEntity = JobEntity.class
        )
    @JoinColumn(
        name = DB_JOB_COL,
        nullable = false
        )
    private Job job ;

    @Override
    public Job job()
        {
        return this.job ;
        }

    @Column(
        name = DB_VAL_COL,
        nullable = true
        )
    private Double value ;

    @Override
    public Double value()
        {
        return this.value ;
        }

    @Override
    public boolean equals(Object that)
        {
        if (this == that)
            {
            return true ;
            }
        if (this.ident == null)
            {
            return false ;
            }
        if (that instanceof TapRowEntity)
            {
            return this.ident.equals(
                ((TapRowEntity)that).ident
                );
            }
        if (that instanceof TapRow)
            {
            return this.ident().equals(
                ((TapRow)that).ident()
                );
            }
        return false ;
        }

    @Override
    public String toString()
        {
        StringBuilder builder = new StringBuilder();
        builder.append(
            "JoinTag["
            );
        builder.append(
            this.ident
            );
        builder.append(
            "]{ "
            );

        builder.append(
            this.job().toString()
            );
        builder.append(
            ", "
            );

        builder.append(
            this.join().toString()
            );
        builder.append(
            ", "
            );
        builder.append(
            this.tag().toString()
            );
        builder.append(
            ", value{"
            );
        builder.append(
            this.value()
            );
        builder.append(
            "}}"
            );
        return builder.toString();
        }
    }

